#include "ps2_client.h"

/*******************************************************************************
 * Function Name  : init
 * Description    : 初始化PS2设备
 * Input          : None
 * Output         : None
 * Return         : None
 *******************************************************************************/
void PS2_Client::init(int pinClk, int pinD) {
    _pinClk = pinClk;
    _pinD = pinD;
    pinMode(_pinClk, OUTPUT_OPEN_DRAIN);
    pinMode(_pinD, OUTPUT_OPEN_DRAIN);
    digitalWrite(_pinClk, HIGH);
    digitalWrite(_pinD, HIGH);

    // 加上延时是因为即使热启动，时钟线也会短时间下拉
    delay(10);
    resetDevice();

    PS2_TX_S = 0; // 发送缓冲开始位置
    PS2_TX_E = 0; // 发送缓冲结束位置

    
}

// 发送一位
// Return : 1： 成功发送  0：被中断
int PS2_Client::send_bit(int bit) {
    digitalWrite(_pinD, bit);
    delayMicroseconds(20);
    digitalWrite(_pinClk, LOW); // 此时主机将读取DATA线
    delayMicroseconds(40);      // 等待主机读取完毕
    digitalWrite(_pinClk, HIGH);
    delayMicroseconds(20);

    return digitalRead(_pinClk);
}

// 读取一位
int PS2_Client::read_bit(uint8_t *bit) {

    delayMicroseconds(20);
    digitalWrite(_pinClk, LOW); // 此时主机将设置DATA线
    delayMicroseconds(40);      // 等待主机设置完毕
    digitalWrite(_pinClk, HIGH);
    delayMicroseconds(20);

    if (!digitalRead(_pinClk)) {
        return 0;
    }

    if (digitalRead(_pinD)) {
        *bit = 0x80;
    } else {
        *bit = 0x00;
    }

    return 1;
}

/*******************************************************************************
 * Function Name  : sendByte
 * Description    : 发送一个字节
 * Input          : timeout：尝试次数
 * Output         : None
 * Return         : 0： success  1：fail
 *******************************************************************************/
int PS2_Client::sendByte(uint8_t data) {

    // 检测1
    if (!digitalRead(_pinClk)) {
        // 被主机抢占
        return 1;
    }

    digitalWrite(_pinD, HIGH);
    delayMicroseconds(50);

    // 检测2
    if (!digitalRead(_pinClk)) {
        // 被主机抢占
        return 1;
    }

    if (!digitalRead(_pinD)) {
        // 主机在输出
        return 1;
    }

    // 现在是clk(1),d(1)
    if (!send_bit(0)) { // 发送起始位
        digitalWrite(_pinD, HIGH);
        return 1;
    }

    uint8_t sendBuf = 0; // 发送的数据
    uint8_t dataChk = 1; // 奇偶校验
    uint8_t dataBit = 0; // 接收/发送的数据位

    // 发送数据
    sendBuf = data;
    for (int i = 0; i < 8; i++) {
        dataBit = sendBuf & 0x01;
        dataChk ^= dataBit;
        if (!send_bit(dataBit)) {
            digitalWrite(_pinD, HIGH);
            return 1;
        }
        sendBuf >>= 1;
    }

    // 发送校验位
    if (!send_bit(dataChk)) {
        digitalWrite(_pinD, HIGH);
        return 1;
    }

    // 查看是否被主机拉低
    digitalWrite(_pinD, HIGH); // 释放
    if (!digitalRead(_pinClk)) {
        return 1;
    }

    // 发送停止位
    delayMicroseconds(20);
    digitalWrite(_pinClk, LOW); // 此时主机将读取DATA线
    delayMicroseconds(40);      // 等待主机读取完毕
    digitalWrite(_pinClk, HIGH);
    delayMicroseconds(40);

    return 0;
}

/*******************************************************************************
 * Function Name  : sendBuffer
 * Description    : 将缓存中的数据发送出去
 * Input          :
 * Output         : None
 * Return         : None
 *******************************************************************************/
void PS2_Client::sendBuffer(void) {
    while (PS2_TX_S != PS2_TX_E) {
        if (0 == sendByte(PS2_TXBuffer[PS2_TX_S])) {
            PS2_TX_S++;
            // 等待主机处理完毕
            while (!digitalRead(_pinClk))
                delayMicroseconds(1);

            // 如果还有要发送的数据
            if (PS2_TX_S != PS2_TX_E) {
                delayMicroseconds(150);
            }
        } else {
            break;
        }
    }
}

/*******************************************************************************
 * Function Name  : readIntoBuffer
 * Description    : 接收数据到缓存
 * Input          :
 * Output         : None
 * Return         : 3: 失败（主机端错误）
 *                  2：失败(校验出错)
 *                  0: 没有数据
 *                  1: success(读到正确数据)
 *******************************************************************************/
int PS2_Client::readIntoBuffer(void) {

    // 检测1
    if (!digitalRead(_pinClk) || digitalRead(_pinD)) {
        // 主机并未输出（不是起始位）
        return 0;
    }

    // 现在是clk(1),d(0), 起始位的上升沿已过
    uint8_t readBuf = 0; // 接收的数据
    uint8_t dataChk = 0; // 奇偶校验
    uint8_t dataBit = 0; // 接收的数据位
    uint8_t err_flg = 0;

    // 读取8位数据
    delayMicroseconds(20);
    for (int i = 0; i < 8; i++) {
        if (!read_bit(&dataBit)) {
            return 0;
        }
        readBuf >>= 1;
        readBuf |= dataBit;
        dataChk ^= dataBit;
    }

    // 读取校验位
    if (!read_bit(&dataBit)) {
        return 0;
    }
    dataChk ^= dataBit;

    // 读取停止位
    if (!read_bit(&dataBit)) {
        return 0;
    }

    // 输出应答位
    send_bit(0);
    digitalWrite(_pinD, HIGH); // 释放D
    delayMicroseconds(20);
    // // 重复产生时钟脉冲，直到数据线被主机释放
    // while (!digitalRead(_pinD)) {
    //     delayMicroseconds(20);
    //     digitalWrite(_pinClk, LOW); // 此时主机将读取DATA线
    //     delayMicroseconds(40);      // 等待主机读取完毕
    //     digitalWrite(_pinClk, HIGH);
    //     delayMicroseconds(20);
    //     err_flg = 1;
    // }
    // if (err_flg) {
    //     return 3;
    // }

    // 校验
    if (dataChk) {
        PS2_RXBuffer = readBuf;
    }

    // 等待主机处理完毕
    delayMicroseconds(70);
    while (!digitalRead(_pinClk))
        delayMicroseconds(1);

    if (dataChk) {
        return 1;
    }

    return 2;
}

